package cn.ava.ymcc.service.impl;

import cn.ava.ymcc.doc.CourseDoc;
import cn.ava.ymcc.dto.AggrDto;
import cn.ava.ymcc.dto.CourseEsSearchDto;
import cn.ava.ymcc.esmapper.HighlightResultMapper;
import cn.ava.ymcc.repository.CourseElasticsearchRepository;
import cn.ava.ymcc.result.PageList;
import cn.ava.ymcc.service.ICourseEsService;
import cn.ava.ymcc.uitls.AggrPageList;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CourseEsServiceImpl implements ICourseEsService {

    @Autowired
    private CourseElasticsearchRepository courseElasticsearchRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @Override
    public void saveCourse(CourseDoc doc) {
//        //创建索引
//        elasticsearchRestTemplate.createIndex(CourseDoc.class);
//        //做文档映射
//        elasticsearchRestTemplate.putMapping(CourseDoc.class);
        courseElasticsearchRepository.save(doc);
    }


    @Override
    public void deleteCourse(CourseDoc doc) {
        courseElasticsearchRepository.deleteById(doc.getId());
    }


    @Override
    public PageList<CourseDoc> search(CourseEsSearchDto doc) {
        // 获取查询条件
        NativeSearchQueryBuilder nativeSearch = new NativeSearchQueryBuilder();
        // 设置分页条件
        nativeSearch.withPageable(PageRequest.of(doc.getPage() - 1,doc.getRows()));
        // 按照字段进行排序
        if (!StringUtils.isBlank(doc.getSortField())){ // 非空校验
            String sortName = "";
            // 使用switch语句进行查询条件排序
            switch (doc.getSortField().toLowerCase()){
                case "xl": sortName = "saleCount";break; // 条件
                case "xp": sortName = "onlineTime";break;
                case "pl": sortName = "commentCount";break;
                case "jg": sortName = "price";break;
                case "rq": sortName = "viewCount";break;
            }
            // 校验是否有查询条件
            if (!StringUtils.isBlank(sortName)) {
                SortOrder order = SortOrder.ASC;
                // 非空校验
                if (!StringUtils.isBlank(doc.getSortType())){
                    // 使用三目条件判断条件是降序还是升序
                    order = "asc".equalsIgnoreCase(doc.getSortType()) ? SortOrder.ASC : SortOrder.DESC;
                }
                // 设置排序
                nativeSearch.withSort(SortBuilders.fieldSort(sortName).order(order));
            }
        }
        // 设置DSL查询与DSL过滤查询条件
        BoolQueryBuilder query = QueryBuilders.boolQuery(); // 获取到DSL查询对象
        // 非空校验
        if (!StringUtils.isBlank(doc.getKeyword())){
            // 关键词进行分词
            query.must(QueryBuilders.matchQuery("name",doc.getKeyword()));
        }
        // 课程等级条件
        if (!StringUtils.isBlank(doc.getGradeName())){
            // term不进行分词,等值查询
            query.must(QueryBuilders.termQuery("gradeName",doc.getGradeName()));
        }
        // 课程类型
        if (doc.getCourseTypeId() != null){
            // term不进行分词,等值查询
            query.must(QueryBuilders.termQuery("courseTypeId",doc.getCourseTypeId()));
        }
        // 最大金额
        if (doc.getPriceMax() != null){
            // range进行范围查询
            query.must(QueryBuilders.rangeQuery("price").lte(doc.getPriceMax()));
        }
        // 最小金额
        if (doc.getPriceMin() != null){
            // range进行范围查询
            query.must(QueryBuilders.rangeQuery("price").gte(doc.getPriceMin()));
        }
        // 设置关键字查询高亮显示
        nativeSearch.withHighlightFields(
                new HighlightBuilder.Field("name")
                        .preTags("<b style='color: red'>")
                        .postTags("</b>"));
        // 添加聚合查询
        nativeSearch.addAggregation(AggregationBuilders
                .terms("chargeAgg")
                .field("chargeName")); // 收费规则
        nativeSearch.addAggregation(AggregationBuilders
                .terms("gradeAgg")
                .field("gradeName")); // 课程等级
        // 设置DSL查询条件
        nativeSearch.withQuery(query);
        NativeSearchQuery build = nativeSearch.build();
        // 返回es查询结果
        AggregatedPage<CourseDoc> page = elasticsearchRestTemplate.queryForPage(build, CourseDoc.class, highlightResultMapper);
        // 处理聚合查询数据
        Aggregations aggregations = page.getAggregations();
        // 从map中获取到结果
        ParsedStringTerms chargeAgg = (ParsedStringTerms)aggregations.asMap().get("chargeAgg");
        ParsedStringTerms gradeAgg = (ParsedStringTerms)aggregations.asMap().get("gradeAgg");
        // 处理返回结果
        Map<String, List<AggrDto>> map = new HashMap<>();
        List<AggrDto> chargeAggs = chargeAgg.getBuckets().stream().map(bucket -> new AggrDto(bucket.getKeyAsString(), bucket.getDocCount())).collect(Collectors.toList());
        List<AggrDto> gradeAggs = gradeAgg.getBuckets().stream().map(bucket -> new AggrDto(bucket.getKeyAsString(), bucket.getDocCount())).collect(Collectors.toList());
        // 放入到map中
        map.put("chargeAgg",chargeAggs);
        map.put("gradeAgg",gradeAggs);
        // 返回数据
        return new AggrPageList(page.getTotalElements(),page.getContent(),map);
    }
}
